package data.composition.factory.impl;

import data.composition.factory.core.*;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author ZhangJinyu
 * @since 2024-12-13
 */
public class FromWrapperImpl<T, R, V> implements FromWrapperInner<T, R, V> {
    private final DataComposition<T> dataComposition;
    private final List<CollectionMappingInner<T, R, V>> collectionMappingInners;
    private final List<MappingInner<T, R, V>> mappingInners;
    private final Collection<R> source;
    private final Function<R, V> kv;
    private Map<V, R> fromMap;
    private Predicate<? super R> predicate;

    public FromWrapperImpl(DataComposition<T> dataComposition, Collection<R> source, Function<R, V> kv) {
        this.dataComposition = dataComposition;
        this.source = source;
        this.kv = kv;
        collectionMappingInners = new LinkedList<>();
        mappingInners = new LinkedList<>();
    }

    @Override
    public Map<V, R> getFromDataMap() {
        if (Objects.isNull(fromMap)) {
            Stream<R> stream = source.stream();
            if (Objects.nonNull(predicate)) {
                stream = stream.filter(predicate);
            }
            fromMap = stream.collect(Collectors.toMap(kv, v -> v));
        }
        return fromMap;
    }

    @Override
    public List<MappingInner<T, R, V>> getMappingInners() {
        return mappingInners;
    }

    @Override
    public List<CollectionMappingInner<T, R, V>> getCollectionMappings() {
        return collectionMappingInners;
    }

    @Override
    public Mapping<T, R, V> key(Function<T, V> dk) {
        MappingImpl<T, R, V> mapping = new MappingImpl<>(dataComposition, dk);
        mappingInners.add(mapping);
        return mapping;
    }

    @Override
    public CollectionMapping<T, R, V> keys(Function<T, Collection<V>> dk) {
        CollectionMappingImpl<T, R, V> collectionMapping = new CollectionMappingImpl<>(dataComposition, dk);
        collectionMappingInners.add(collectionMapping);
        return collectionMapping;
    }

    @Override
    public FromWrapper<T, R, V> filter(Predicate<? super R> predicate) {
        this.predicate = predicate;
        return this;
    }

}
